# Pongathon
# Version 1.4.1
# Copyright 2014 Josef J. Polak III
# Pongathon is distributed under the terms of the GNU General Public License

# This file is part of Pongathon.

# Pongathon is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Pongathon is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

# Views for Pongathon
# Includes the sound codes

import os, sys
import events
import pygame

def load_image(name, colorkey=None):
	fullname = os.path.join('data', 'images')
	fullname = os.path.join(fullname, name)
	try:
		image = pygame.image.load(fullname)
	except pygame.error, message:
		print 'Cannot load image:', fullname
		raise SystemExit, message
	image = image.convert()
	if colorkey is not None:
		if colorkey is -1:
			colorkey = image.get_at((0, 0))
			image.set_colorkey(colorkey, pygame.RLEACCEL)
	return image, image.get_rect()


def simple_load_image(name):
	"""Same as load_image, except no pixel format conversion or colorkey.
	Intended to be used only for the window icon."""

	fullname = os.path.join('data', 'images')
	fullname = os.path.join(fullname, name)
	try:
		image = pygame.image.load(fullname)
	except pygame.error, message:
		print 'Cannot load image:', fullname
		raise SystemExit, message
	return image

def load_sound(name):
	class NoneSound:
		def play(self): pass
	if not pygame.mixer:
		return NoneSound()
	fullname = os.path.join('data', 'sounds')
	fullname = os.path.join(fullname, name)
	try:
		sound = pygame.mixer.Sound(fullname)
	except pygame.error, message:
		print 'Cannot load sound:'
		raise SystemExit, message # Something less drastic?
	return sound

class PygameGraphicalView:
	"""The Pygame Graphical View."""

	def __init__(self, evManager, game, width=640, height=480):
		from pygame import display
		from pygame import font
		
		self.evManager = evManager
		self.evManager.RegisterListener(self)
		
		self.game = game

		pygame.init()
		self.width = width
		self.height = height
		pygame.display.set_caption('Pongathon! v.1.4.1')
		pygame.display.set_icon(simple_load_image('ball.png'))
		pygame.mouse.set_visible(False)
		self.screen = pygame.display.set_mode((self.width, self.height))
		self.background = pygame.Surface(self.screen.get_size())
		self.background = self.background.convert()
		self.bgcolor = (0, 60, 0)
		self.background.fill(self.bgcolor)

		self.listenmode = 'intro'
		self.flippedonce = False
		self.gamestarted = False

	def Notify(self, event):
		if isinstance(event, events.Tick):
			if self.listenmode == 'intro':
				self.ListenIntro()
			elif self.listenmode == 'playing':
				self.ListenPlaying()
			elif self.listenmode == 'paused':
				self.ListenPaused()
			elif self.listenmode == 'over':
				self.ListenOver()
		elif isinstance(event, events.SetStateRequest):
			self.flippedonce = False
			self.listenmode = event.state
		elif isinstance(event, events.PlayerScored):
			self.p1score = self.game.p1.score
			self.p2score = self.game.p2.score
			self.flippedonce = False
		elif isinstance(event, events.SetThemeRequest):
			if event.num == 1:
				self.theme = 1
				self.bgcolor = (0, 60, 0)
				if self.gamestarted == True:
					self.makesprites(self.theme)
				self.flippedonce = False
			elif event.num == 2:
				self.theme = 2
				self.bgcolor = (0, 0, 0)
				if self.gamestarted == True:
					self.makesprites(self.theme)
				self.flippedonce = False
		elif isinstance(event, events.DisplayModeRequest):
			if self.listenmode != 'intro':
				pass
			else:
				if event.full == True:
					self.screen = pygame.display.set_mode(
							event.res,
							pygame.FULLSCREEN)
					self.flippedonce = False
				else:
					self.screen = pygame.display.set_mode(
							event.res)
					self.flippedonce = False
	
	def ListenIntro(self):
		if self.flippedonce is False:
			self.background.fill(self.bgcolor)
			self.screen.blit(self.background, (0, 0))
			self.rendertext("Pongathon! v.1.4.1", 
					"Hit 1 for Single Player, 2 for Hot Seat")
			pygame.display.flip()
			self.flippedonce = True

	def ListenPaused(self):
		if self.flippedonce is False:
			self.rendertext("Game Paused!",
					"Hit Return to Continue")
			pygame.display.flip()
			self.flippedonce = True

	def ListenOver(self):
		if self.flippedonce is False:
			self.background.fill(self.bgcolor)
			self.screen.blit(self.background, (0, 0))
			if self.game.p1.score > self.game.p2.score:
				self.rendertext("Player 1 Wins!",
					"Hit Return to play again.")
			elif self.game.p2.score > self.game.p1.score:
				self.rendertext("Player 2 Wins!",
						"Hit Return to play again.")
			self.p1score = self.p2score = 0
			pygame.display.flip()
			self.flippedonce = True

	def ListenPlaying(self):
		if self.gamestarted is False:
			self.makesprites(self.theme)
			self.gamestarted = True
		
		# Draw everything
		if self.flippedonce is False:
			self.background.fill(self.bgcolor)
			if self.theme == 1:
				pygame.draw.line(self.background, (255,255,255)
						, (0,302), (640, 302), 5)
				pygame.draw.line(self.background, (255,255,255)
						, (320, 124), (320, 480), 5)
				pygame.draw.line(self.background, (255,255,255)
						, (2, 124), (2, 480), 5)
				pygame.draw.line(self.background, (255,255,255)
						, (0, 124), (640, 124), 5)
				pygame.draw.line(self.background, (255,255,255)
						, (0, 477), (640, 477), 5)
				pygame.draw.line(self.background, (255,255,255)
						, (637, 124), (637, 480), 5)
			elif self.theme == 2:
				pygame.draw.line(self.background, (255,255,255)
						, (320,124), (320, 160), 5)
				pygame.draw.line(self.background, (255,255,255)
						, (320,195), (320, 231), 5)
				pygame.draw.line(self.background, (255,255,255)
						, (320,267), (320, 304), 5)
				pygame.draw.line(self.background, (255,255,255)
						, (320,340), (320, 377), 5)
				pygame.draw.line(self.background, (255,255,255)
						, (320,413), (320, 450), 5)
			self.p1score = self.game.p1.score
			self.p2score = self.game.p2.score
			self.screen.blit(self.background, (0, 0))
			self.rendertext("P1: %s                                                                          P2: %s" % (self.p1score, self.p2score))
			self.p1sprite.update(self.game.p1.paddle.center)
			self.p2sprite.update(self.game.p2.paddle.center)
			self.ballsprite.update(self.game.ball.center)
			self.sprites.draw(self.screen)
			pygame.display.flip()
			self.flippedonce = True
		elif self.flippedonce is True:
			self.sprites.clear(self.screen, self.background)
			self.p1sprite.update(self.game.p1.paddle.center)
			self.p2sprite.update(self.game.p2.paddle.center)
			self.ballsprite.update(self.game.ball.center)
			pygame.display.update(self.sprites.draw(self.screen))

	def rendertext(self, bigstring, smallstring=None):
		"""Render one or two strings of text. First one is centered
		and pretty large. Second is most of the way to the bottom
		and smaller"""

		if pygame.font:
			bigfont = pygame.font.Font(None, 36)
			bigtext = bigfont.render(bigstring, 1, (255, 255, 255))
			bigtextpos = bigtext.get_rect(centerx=320, centery=62)
			self.screen.blit(bigtext, bigtextpos)

			if smallstring is not None:
				smallfont = pygame.font.Font(None, 18)
				smalltext = smallfont.render(smallstring, 1, 
						(255, 255, 255))
				smalltextpos = smalltext.get_rect(centerx=320,
						centery=93)
				self.screen.blit(smalltext, smalltextpos)

	def makesprites(self, num):
		"""Define sprites on theme change."""
		if num == 1:	
			self.p1sprite = PaddleSprite(self.game.p1.paddle.center)
			self.p2sprite = PaddleSprite(self.game.p2.paddle.center)
			self.p1sprite.image = pygame.transform.flip(
					self.p2sprite.image, 1, 0)
			self.ballsprite = BallSprite(self.game.ball.center)

		elif num == 2:
			self.p1sprite = ArcadePaddleSprite(
					self.game.p1.paddle.center)
			self.p2sprite = ArcadePaddleSprite(
					self.game.p2.paddle.center)
			self.ballsprite = ArcadeBallSprite(
					self.game.ball.center)

		self.sprites = pygame.sprite.RenderUpdates((self.p1sprite, 
			self.p2sprite, self.ballsprite))
		self.allrects = (self.p1sprite.rect, self.p2sprite.rect,
				self.ballsprite.rect)


class PaddleSprite(pygame.sprite.Sprite):
	"""Sprite representing the Paddle class from model.py"""
	
	def __init__(self, pos):
		pygame.sprite.Sprite.__init__(self)
		self.image, self.rect = load_image('paddle.png', -1)
		self.rect.center = pos

	def update(self, pos):
		self.rect.center = pos

class BallSprite(pygame.sprite.Sprite):
	"""Sprite representing the Ball class from model.py"""
	
	def __init__(self, pos):
		pygame.sprite.Sprite.__init__(self)
		self.image, self.rect = load_image('ball.png', -1)
		self.rect.center = pos

	def update(self, pos):
		self.rect.center = pos

class ArcadePaddleSprite(pygame.sprite.Sprite):
	"""Sprite representing the Paddle class from model.py, for the arcade
	view. Just a boring white rectangle."""

	def __init__(self, pos):
		pygame.sprite.Sprite.__init__(self)
		paddlesurf = pygame.Surface((22, 90))
		paddlesurf.fill((255, 255, 255))
		self.image = paddlesurf
		self.rect = pygame.Rect((0,0), (22, 90)) 
		self.rect.center = pos

	def update(self, pos):
		self.rect.center = pos

class ArcadeBallSprite(pygame.sprite.Sprite):
	"""Sprite representing the Ball class from modely.py, for the arcade
	view. This one is a boring white square!"""

	def __init__(self, pos):
		pygame.sprite.Sprite.__init__(self)
		ballsurf = pygame.Surface((24, 24))
		ballsurf.fill((255, 255, 255))
		self.image = ballsurf
		self.rect = pygame.Rect((0,0), (24, 24))
		self.rect.center = pos

	def update(self, pos):
		self.rect.center = pos


class PygameSoundView:
	"""Sound code using pygame.mixer"""

	def __init__(self, evManager):
		from pygame import mixer
		pygame.mixer.init(44100)

		self.evManager = evManager
		self.evManager.RegisterListener(self)

	def Notify(self, event):
		if isinstance(event, events.SetThemeRequest):
			if event.num == 1:
				self.wall = load_sound('bump.wav')
				self.p1 = load_sound('paddle2.wav')
				self.p2 = load_sound('paddle1.wav')
				self.p1score = load_sound('yay.wav')
				self.p2score = load_sound('boo.wav')
			elif event.num == 2:
				self.wall = load_sound('beep.wav')
				self.p1 = load_sound('beepup.wav')
				self.p2 = load_sound('beepdown.wav')
				self.p1score = load_sound('p1score.wav')
				self.p2score = load_sound('p2score.wav')
		elif isinstance(event, events.BallCollision):
			if event.object == 'wall':
				self.wall.play()
			elif event.object == 'p1' or event.object == 'p1lc':
				self.p1.play()
			elif event.object == 'p1rc':
				self.p1.play()
			elif event.object == 'p2' or event.object == 'p2lc':
				self.p2.play()
			elif event.object == 'p2rc':
				self.p2.play()
		elif isinstance(event, events.PlayerScored):
			if event.num == 1:
				self.p1score.play()
			elif event.num == 2:
				self.p2score.play()
